﻿/*
JSMock 1.2.2, a mock object library for JavaScript 
Copyright (C) 2006 Justin DeWind 

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
*/
JSMock={extend:function(a){var b=new MockControl;a.createMock=function(c){return b.createMock(c)};a.resetMocks=function(){b.reset()};a.verifyMocks=function(){b.verify()};if(a.tearDown){if(a.tearDown.constructor==Function){a.__oldTearDown__=a.tearDown;a.tearDown=function(){a.__oldTearDown__();a.verifyMocks()}}}else a.tearDown=function(){a.verifyMocks()}}};function MockControl(){this.__expectationMatcher=new ExpectationMatcher;this.__lastCallName=this.__lastMock=null}
MockControl.prototype={createMock:function(a){var b={calls:[],expects:function(){this.__recording=true;return this},__recording:false};b.expect=b.expects;if(a!=null)if(typeof a=="function"){this.__createMethods(a,b);this.__createMethods(new a,b)}else if(typeof a=="object")this.__createMethods(a,b);else throw Error("Cannot mock out a "+typeof a);var c=this;b.addMockMethod=function(d){c.__createMethod(c,b,d)};return b},andReturn:function(a){this.__verifyLastMockNotNull("Cannot set return value without an expectation");
this.__initializeReturnExpectationForMock();this.__lastMock.calls[this.__lastCallName].push(function(){return a})},andThrow:function(a){this.__verifyLastMockNotNull("Cannot throw error without an expectation");this.__initializeReturnExpectationForMock();this.__lastMock.calls[this.__lastCallName].push(function(){throw Error(a);})},andStub:function(a){this.__verifyLastMockNotNull("Cannot stub without an expectation");if(typeof a!="function")throw Error("Stub must be a function");this.__initializeReturnExpectationForMock();
this.__lastMock.calls[this.__lastCallName].push(function(){return a.apply(this,arguments)})},reset:function(){this.__expectationMatcher.reset()},verify:function(){if(this.__expectationMatcher.matches())this.__expectationMatcher.reset();else{discrepancy=this.__expectationMatcher.discrepancy();message=discrepancy.message;method=discrepancy.behavior.method;formattedArgs=ArgumentFormatter.format(discrepancy.behavior.methodArguments);this.__expectationMatcher.reset();throw Error(message+": "+method+"("+
formattedArgs+")");}},__createMethods:function(a,b){for(property in a)this.__isPublicMethod(a,property)&&this.__createMethod(this,b,property)},__createMethod:function(a,b,c){b[c]=function(){if(b.__recording){a.__lastMock=b;a.__lastCallName=c;a.__expectationMatcher.addExpectedMethodCall(b,c,arguments);b.__recording=false;return a}else{a.__expectationMatcher.addActualMethodCall(b,c,arguments);if(b.calls[c]!=null){returnValue=b.calls[c].shift();if(typeof returnValue=="function")return returnValue.apply(this,
arguments)}}}},__isPublicMethod:function(a,b){try{return typeof a[b]=="function"&&b.charAt(0)!="_"}catch(c){return false}},__verifyLastMockNotNull:function(a){if(this.__lastMock==null)throw Error(a);},__initializeReturnExpectationForMock:function(){if(typeof this.__lastMock.calls[this.__lastCallName]=="undefined")this.__lastMock.calls[this.__lastCallName]=[]}};function ExpectationMatcher(){this.__expectationBehaviorList=[];this.__actualBehaviorList=[];this.__discrepancy=null}
ExpectationMatcher.prototype={addExpectedMethodCall:function(a,b,c){this.__expectationBehaviorList.push(new InvocationBehavior(a,b,c))},addActualMethodCall:function(a,b,c){this.__actualBehaviorList.push(new InvocationBehavior(a,b,c))},matches:function(){var a=this,b=true;this.__expectationBehaviorList.eachIndexForJsMock(function(c,d){var e=a.__actualBehaviorList.length>c?a.__actualBehaviorList[c]:null;if(b)if(e===null){a.__discrepancy=new Discrepancy("Expected function not called",d);b=false}else if(d.method!=
e.method){a.__discrepancy=new Discrepancy("Surprise call",e);b=false}else if(d.caller!=e.caller){a.__discrepancy=new Discrepancy("Surprise call from unexpected caller",e);b=false}else if(!a.__matchArguments(d.methodArguments,e.methodArguments)){a.__discrepancy=new Discrepancy("Unexpected Arguments",e);b=false}});if(this.__actualBehaviorList.length>this.__expectationBehaviorList.length&&b){this.__discrepancy=new Discrepancy("Surprise call",this.__actualBehaviorList[this.__expectationBehaviorList.length]);
b=false}return b},reset:function(){this.__expectationBehaviorList=[];this.__actualBehaviorList=[];this.__discrepancy=null},discrepancy:function(){return this.__discrepancy},__matchArguments:function(a,b){var c=this.__convertArgumentsToArray(a),d=this.__convertArgumentsToArray(b);return ArgumentMatcher.matches(c,d)},__convertArgumentsToArray:function(a){for(var b=[],c=0;c<a.length;c++)b[c]=a[c];return b}};function InvocationBehavior(a,b,c){this.caller=a;this.method=b;this.methodArguments=c}
function TypeOf(a){if(typeof a!="function")throw Error("Can only take constructors");this.type=a}TypeOf.isA=function(a){return new TypeOf(a)};
ArgumentMatcher={matches:function(a,b){return this.__delegateMatching(a,b)},__delegateMatching:function(a,b){return a==null?this.__match(a,b):a.constructor==TypeOf?this.__match(a.type,b.constructor):a.constructor==Array?this.__matchArrays(a,b):this.__match(a,b)},__match:function(a,b){return a==b},__matchArrays:function(a,b){if(b==null)return false;if(b.constructor!=Array)return false;if(a.length!=b.length)return false;for(var c=0;c<a.length;c++)if(!this.__delegateMatching(a[c],b[c]))return false;
return true}};function Discrepancy(a,b){if(b.constructor!=InvocationBehavior)throw Error("The behavior can only be an InvocationBehavior object");this.message=a;this.behavior=b}
ArgumentFormatter={format:function(a){for(var b="",c=0;c<a.length;c++)if(a[c]==null)b+=b==""?"null":", null";else if(a[c].constructor==TypeOf||a[c].constructor==Function){var d=a[c].constructor==TypeOf?a[c].type:a[c];b+=b==""?this.__formatFunction(d):", "+this.__formatFunction(d)}else b+=typeof a[c]=="string"?b==""?'"'+a[c].toString()+'"':', "'+a[c].toString()+'"':a[c].constructor==Array?b==""?"["+this.format(a[c])+"]":", ["+this.format(a[c])+"]":b==""?a[c].toString():", "+a[c].toString();return b},
  __formatFunction: function (a) { if (a == Array) return "Array"; else if (a == Date) return "Date"; else if (a == Object) return "Object"; else if (a == String) return "String"; else if (a == Function) return "Function"; else if (a == RegExp) return "RegExp"; else if (a == Error) return "Error"; else if (a == Number) return "Number"; else if (a == Boolean) return "Boolean"; a = a.toString().match(/function (\w+)/); return a == null ? "{{Closure}}" : a[1] } 
}; Array.prototype.eachIndexForJsMock = function (a) { for (var b = 0; b < this.length; b++) a(b, this[b]) };
